import json
import math
import traceback

from flask import Blueprint, request, jsonify
from controllers.common import *
from controllers.db import *
from controllers.dynamic_sub_game_generator import generator_map

import logging
import copy

dynamic_sub_game_master_api = Blueprint('dynamic_sub_game_master_api', __name__)
dynamic_sub_game_publish_api = Blueprint('dynamic_sub_game_publish_api', __name__)


@dynamic_sub_game_master_api.route('/dynamic_sub_game', methods=['POST'])
def dynamic_sub_game_master():
    response = {
        'status': 'success'
    }

    try:
        params = json.loads(request.data)
        action = params['action']
        if action == 'get_part_config':
            part = params['part']
            updated_time = params['time']
            with open(STATIC_PATH + 'dynamic_sub_game/config.json', encoding='UTF-8') as F:
                config_data = json.load(F)
            if part not in config_data:
                return jsonify({
                    'status': 'PartNotInConfigFile'
                })

            if updated_time == -1:
                query_data = DynamicSubGame.query.filter_by(part=part).order_by(DynamicSubGame.updated_at.desc()).first()
            else:
                query_data = DynamicSubGame.query.filter_by(part=part, updated_at=updated_time).first()
            if query_data is None:
                return jsonify({
                    'status': 'PartNotInDatabase'
                })
            response['data'] = json.loads(query_data.data)
            response['time'] = query_data.updated_at
            response['parse_time'] = fomat_timestamp(query_data.updated_at)
            response['config'] = config_data[part]
        elif action == 'get_storage':
            type = params['type']
            query_data = DynamicSubGameStorage.query.filter_by(type=type).first()
            if query_data is None:
                return jsonify({
                    'status': 'TypeNotInDatabase'
                })
            response['data'] = json.loads(query_data.data)
        elif action == 'save_check_update_time':
            part = params['part']
            check_time = params['time']
            query_data = DynamicSubGame.query.filter_by(part=part).order_by(DynamicSubGame.updated_at.desc()).first()
            if query_data is None:
                return jsonify({
                    'status': 'PartNotInDatabase'
                })
            if query_data.updated_at > check_time:
                response['status'] = 'fail'
                response['time'] = query_data.updated_at
                response['parse_time'] = fomat_timestamp(query_data.updated_at)
        elif action == 'save_part_config':
            part = params['part']
            # query_data = DynamicSubGame.query.filter_by(part=part).first()
            # if query_data is None:
            #     return jsonify({
            #         'status': 'PartNotInDatabase'
            #     })
            # query_data.data = json.dumps(params['data'])
            current_time = int(time.time())
            new_data = DynamicSubGame(
                part=part,
                data=json.dumps(params['data']),
                updated_at=current_time
            )
            db.session.add(new_data)
            db.session.commit()
            response['time'] = current_time
            response['parse_time'] = fomat_timestamp(current_time)
        elif action == 'save_storage':
            type = params['type']
            query_data = DynamicSubGameStorage.query.filter_by(type=type).first()
            if query_data is None:
                return jsonify({
                    'status': 'TypeNotInDatabase'
                })
            query_data.data = json.dumps(params['data'])
            db.session.commit()
        elif action == 'new_storage':
            type = params['type']
            query_data = DynamicSubGameStorage.query.filter_by(type=type).first()
            if query_data is None:
                return jsonify({
                    'status': 'TypeNotInDatabase'
                })
            storage_data = json.loads(query_data.data)
            storage_data = storage_data + params['data']
            query_data.data = json.dumps(storage_data)
            db.session.commit()
        elif action == 'get_part_history':
            part = params['part']
            return_result = []
            query_data = DynamicSubGame.query.filter_by(part=part).order_by(DynamicSubGame.updated_at.desc()).all()
            for i in query_data:
                return_result.append({
                    'time': i.updated_at,
                    'parse_time': fomat_timestamp(i.updated_at)
                })
            response['data'] = return_result
        return jsonify(response)
    except Exception as e:
        logging.exception(e)
        return {
            'status': 500,
            'message': traceback.format_exc()
        }


@dynamic_sub_game_publish_api.route('/dynamic_sub_game_down', methods=['POST'])
def dynamic_sub_game_publish():
    def default_no_generator_exist(all_data, root):
        return 'fail', '无法访问生成该配置的代码'

    response = {
        'status': 'success'
    }

    try:
        params = json.loads(request.data)
        action = params['action']

        with open(STATIC_PATH + 'dynamic_sub_game/config.json', encoding='UTF-8') as F:
            config_data = json.load(F)
        publish_status = {}
        all_data = {}
        dynamic_sub_game = {}
        for i in config_data:
            # prepare before generation
            current_part = i
            publish_status[current_part] = {
                'status': 'wait',
                'message': ''
            }

            # get latest data in database
            query_data = DynamicSubGame.query.filter_by(part=current_part).order_by(
                DynamicSubGame.updated_at.desc()).first()
            if query_data is None:
                publish_status[current_part] = {
                    'status': 'error',
                    'message': '获取配置数据失败，无法在数据库中获取记录'
                }
                all_data[current_part] = {}
                continue
            try:
                all_data[current_part] = json.loads(query_data.data)
            except Exception as e:
                logging.exception(e)
                publish_status[current_part] = {
                    'status': 'error',
                    'message': '解析配置失败'
                }
                all_data[current_part] = {}
        for i in config_data:
            # prepare before generation
            current_part = i
            if publish_status[current_part]['status'] not in ['fail', 'error']:
                generator = generator_map.get(current_part, default_no_generator_exist)
                (gen_status, gen_message) = generator(all_data, dynamic_sub_game)
                publish_status[current_part]['status'] = gen_status
                publish_status[current_part]['message'] = gen_message

        # 补充某些可能废弃的字段内容
        with open(STATIC_PATH + 'dynamic_sub_game/part_data.json', encoding='UTF-8') as f:
            part_data = json.load(f)
        for part_k, part_v in part_data.items():
            if part_k not in dynamic_sub_game:
                dynamic_sub_game[part_k] = part_v

        response['generation_status'] = publish_status
        response['generation_data'] = {
            'open_control': dynamic_sub_game
        }

        if action == 'export':
            return jsonify(response)

        elif action == 'download':
            download_allow = True
            download_response = {"msg": "发布成功", "ret": 1}
            for v in response['generation_status'].values():
                if v['status'] != 'success':
                    download_allow = False
                    break
            if download_allow:
                DownLoad(
                    'dynamic_sub_game',
                    response['generation_data'],
                    is_push=1)
            else:
                download_response = {"msg": "发布失败", "ret": 0}
            download_response['generation_status'] = response['generation_status']
            return jsonify(download_response)

    except Exception as e:
        logging.exception(e)
        return {
            'status': 500,
            'message': traceback.format_exc()
        }
